import javax.swing.*;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


class ServerRecieveThread extends Thread{
    ObjectInputStream in;
    PongGamePanel game;
    ServerRecieveThread(ObjectInputStream i, PongGamePanel game){
        in=i;
        this.game=game;
    }
    GameState gs;
    @Override
    public void run() {
        try {
            while (true){
                gs = (GameState) in.readObject();
                System.out.println(gs);
                if(gs!=null){
                    synchronized (game){
                        game.setPlayerState(gs);
                    }
                }
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

}
class ServerThread extends Thread{
    Socket client;
    ObjectOutputStream out;
    JFrame main;
    PongGamePanel game;
    ObjectInputStream in;

    ServerThread(Socket s, JFrame m){
        client = s;
        main = m;
    }

    @Override
    public void run() {
        startGame();
        System.out.println("GAMESTArT");

        try {
            out = new ObjectOutputStream(client.getOutputStream());
            in = new ObjectInputStream(client.getInputStream());
            ServerRecieveThread serverRecieveThread=new ServerRecieveThread(in,game);
            serverRecieveThread.start();
            while(true){
                out.writeObject(game.getGameState());
                out.flush();
                Thread.sleep(10);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

    }

    private void startGame() {
        game = new PongGamePanel(false,0);
        game.setBounds(0,0,800,600);
        main.getContentPane().removeAll();
        main.getContentPane().add(game);
        game.setVisible(true);
        main.repaint();
        game.requestFocus();
    }

}

public class TCPServer implements Runnable{
    private static final int PORT = 9527;
    private List<Socket> clients;
    private ServerSocket serverSocket;
    private ExecutorService executor;
    private JFrame main;
    private InetAddress local;
    TCPServer(JFrame m, InetAddress local){
        main = m;
        clients = new ArrayList<>();
        this.local=local;
    }
    public void start() {
        executor = Executors.newFixedThreadPool(5);
        try {
            serverSocket = new ServerSocket(PORT,0,local);
            System.out.println("Server started. Waiting for clients...");

            while (true) {
                Socket clientSocket = serverSocket.accept();
                clients.add(clientSocket);

                System.out.println("Client connected: " + clientSocket.getInetAddress());
                executor.execute(new ServerThread(clientSocket, main));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void stop(){
        executor.shutdown();
        for(Socket s: clients){
            try{
                s.close();
            }catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        clients.clear();
    }

    @Override
    public void run() {
        start();
    }
}
